package com.fis.vaadin;

import java.util.Iterator;
import java.util.Map;
import java.util.Vector;

import com.fis.vaadin.define.ControlDefines;
import com.fis.vaadin.define.Properties;
import com.fis.vaadin.define.Sections;
import com.fis.vaadin.utils.StringUtil;
import com.fss.dictionary.Dictionary;
import com.fss.dictionary.DictionaryNode;
import com.vaadin.terminal.ThemeResource;
import com.vaadin.ui.AbstractComponent;
import com.vaadin.ui.AbstractField;
import com.vaadin.ui.AbstractTextField;
import com.vaadin.ui.Component;
import com.vaadin.ui.ComponentContainer;
import com.vaadin.ui.Field;

import eu.livotov.tpt.i18n.TM;

public class VaadinFormBuilderImpl implements VaadinFormBuilder {

	@SuppressWarnings("unused")
	private ComponentContainer form;
	private ControlCreator controlCreator;
	private LayoutBuilderImpl layoutBuilder;
	private VaadinFormData formData;

	@SuppressWarnings("rawtypes")
	@Override
	public boolean isValidate(Component form, VaadinFormData formData,
			Dictionary dictionary) throws Exception {

//		Iterator iter = null;
//		Component cmp = null;
//
//		while ((iter = formData.getVtControlList().iterator()).hasNext()) {
//
//			cmp = (Component) iter.next();
//
//			if (cmp instanceof AbstractField) {
//
//				if (!((AbstractField) cmp).isValid())
//					return false;
//
//			}
//
//		}
//
//		while ((iter = formData.getVtFieldList().iterator()).hasNext()) {
//
//			cmp = (Component) iter.next();
//
//			if (cmp instanceof AbstractField) {
//
//				if (!((AbstractField) cmp).isValid())
//					return false;
//
//			}
//
//		}

		return true;
	}

	@Override
	public boolean isValidate(Component form, VaadinFormData formData,
			Dictionary dictionary, String[] fields) throws Exception {

//		Component cmp = null;
//
//		for (String field : fields) {
//
//			cmp = (Component) formData.getMapControlList().get(field);
//
//			if (cmp instanceof AbstractField) {
//
//				if (!((AbstractField) cmp).isValid())
//					return false;
//			}
//
//			cmp = (Component) formData.getMapFieldList().get(field);
//
//			if (cmp instanceof AbstractField) {
//
//				if (!((AbstractField) cmp).isValid())
//					return false;
//			}
//
//		}

		return true;

	}

	@SuppressWarnings("rawtypes")
	@Override
	public boolean isValidateExclude(Component form, VaadinFormData formData,
			Dictionary dictionary, String[] fields) throws Exception {

//		Iterator iter = null;
//		Component cmp = null;
//		boolean isContinue = false;
//
//		iter = formData.getMapControlList().keySet().iterator();
//
//		while (iter.hasNext()) {
//
//			String key = (String) iter.next();
//			isContinue = false;
//
//			for (String current : fields) {
//				if (current.equals(key)) {
//					isContinue = true;
//					break;
//				}
//			}
//
//			if (isContinue)
//				continue;
//
//			cmp = (Component) formData.getMapControlList().get(key);
//
//			if (cmp instanceof AbstractField) {
//
//				if (!((AbstractField) cmp).isValid())
//					return false;
//			}
//
//		}
//
//		iter = formData.getMapFieldList().keySet().iterator();
//
//		while (iter.hasNext()) {
//
//			String key = (String) iter.next();
//			isContinue = false;
//
//			for (String current : fields) {
//				if (current.equals(key)) {
//					isContinue = true;
//					break;
//				}
//			}
//
//			if (isContinue)
//				continue;
//
//			cmp = (Component) formData.getMapFieldList().get(key);
//
//			if (cmp instanceof AbstractField) {
//
//				if (!((AbstractField) cmp).isValid())
//					return false;
//			}
//
//		}

		return true;
	}

	@SuppressWarnings("rawtypes")
	@Override
	public void buildForm(ComponentContainer form, VaadinFormData formData,
			Dictionary dictionary) throws Exception {
		this.formData = formData;
		DictionaryNode dnNode = dictionary
				.getChildIgnoreCase(Sections.DEFINE_FIELD);
		if (dnNode != null) {
			Vector vtFields = dnNode.getChildList();

			for (int i = 0; i < vtFields.size(); i++)
				createControl(form, (DictionaryNode) vtFields.elementAt(i),
						formData.getVtControlList(),
						formData.getMapControlList(),
						formData.getMapContronDefinition(),
						formData.getVtFieldList(), formData.getMapFieldList(),
						formData.getMapFieldDefinition());
		}

		dnNode = dictionary.getChildIgnoreCase(Sections.DEFINE_CONTROL);
		if (dnNode != null) {
			Vector vtControls = dnNode.getChildList();

			for (int i = 0; i < vtControls.size(); i++)
				createControl(form, (DictionaryNode) vtControls.elementAt(i),
						formData.getVtControlList(),
						formData.getMapControlList(),
						formData.getMapContronDefinition(), null, null, null);
		}

		dnNode = dictionary.getChildIgnoreCase(Sections.DEFINE_LAYOUT);
		if (dnNode != null) {

			layoutBuilder.buildFormLayout(form, formData, dnNode);

		}

	}

	@SuppressWarnings({ "unchecked", "rawtypes" })
	private void createControl(ComponentContainer component,
			DictionaryNode dnControl, Vector vtControlList, Map mapControlList,
			Map mapControlDefinition, Vector vtFieldList, Map mapFieldList,
			Map mapFieldDefinition) throws Exception {

		String strName = dnControl.getValue();
		if (!strName.equals("") && mapControlList.get(strName) != null)
			throw new DuplicateException(String.format(
					"Control %s already defined\n\tAt: %s", strName,
					dnControl.getTrace()));

		String strType = dnControl.mstrName.toLowerCase();
		Component cmp = null;

		if (strType.equals(ControlDefines.TEXT))
			cmp = controlCreator.createTextControl(component, dnControl);
		else if (strType.equals(ControlDefines.TEXT_AREA))
			cmp = controlCreator.createTextAreaControl(component, dnControl);
		else if (strType.equals(ControlDefines.COMBOBOX))
			cmp = controlCreator.createComboBoxControl(component, dnControl);
		else if (strType.equals(ControlDefines.DATE))
			cmp = controlCreator.createDateControl(component, dnControl);
		else if (strType.equals(ControlDefines.TABLE))
			cmp = controlCreator.createTableControl(component, dnControl);
		else if (strType.equals(ControlDefines.BUTTON))
			cmp = controlCreator.createButtonControl(component, dnControl);
		else if (strType.equals(ControlDefines.NUMBER))
			cmp = controlCreator.createNumberControl(component, dnControl);
		else if (strType.equals(ControlDefines.CHECKBOX))
			cmp = controlCreator.createCheckBoxControl(component, dnControl);
		else if (strType.equals(ControlDefines.TREE))
			cmp = controlCreator.createTreeControl(component, dnControl);
		else if (strType.equals(ControlDefines.LINK))
			cmp = controlCreator.createLinkControl(component, dnControl);
		else if (strType.equals(ControlDefines.EMBEDDED))
			cmp = controlCreator.createEmbeddedControl(component, dnControl);
		else if (strType.equals(ControlDefines.RICH_TEXT_AREA))
			cmp = controlCreator.createRichTextControl(component, dnControl);
		else if (strType.equals(ControlDefines.LIST_SELECT))
			cmp = controlCreator.createListSelectControl(component, dnControl);
		else if (strType.equals(ControlDefines.OPTION_GROUP))
			cmp = controlCreator.createOptionGroupControl(component, dnControl);
		else if (strType.equals(ControlDefines.SLIDER))
			cmp = controlCreator.createSliderControl(component, dnControl);
		else if (strType.equals(ControlDefines.TREE_TABLE))
			cmp = controlCreator.createTreeTableControl(component, dnControl);
		else if (strType.equals(ControlDefines.MENUBAR))
			cmp = controlCreator.createMenuBarControl(component, dnControl);
		else if (strType.equals(ControlDefines.USER_DEFINED))
			cmp = controlCreator.createUserDefinedControl(component, dnControl);
		else
			throw new UnsupportedException(String.format(
					"Control %s with type %s is unsupported\n\tAt: %s",
					strName, strType, dnControl.getTrace()));

		applyCommonAttribute(cmp, dnControl);

		vtControlList.addElement(cmp);
		mapControlList.put(strName, cmp);
		mapControlDefinition.put(strName, dnControl);

		if (vtFieldList != null) {
			vtFieldList.addElement(cmp);
			mapFieldList.put(strName, dnControl);
			mapFieldDefinition.put(strName, cmp);
		}

	}

	/**
	 * <b>Modified by VinhNDQ</b>
	 * 
	 * Find property for field set field has check unique
	 * 
	 * @date 10/12/2012
	 */
	private void applyCommonAttribute(Component component,
			DictionaryNode dictionaryNode) throws Exception {

		String strWidth = dictionaryNode.getStringIgnoreCase(Properties.WIDTH);
		String strHeight = dictionaryNode
				.getStringIgnoreCase(Properties.HEIGHT);
		String strIcon = dictionaryNode.getStringIgnoreCase(Properties.ICON);
		String strResource = dictionaryNode
				.getStringIgnoreCase(Properties.RESOURCE);
		String strDescription = dictionaryNode
				.getStringIgnoreCase(Properties.DESCRIPTION);
		String strTitle = dictionaryNode.getStringIgnoreCase(Properties.TITLE);
		String strRequiredMessage = dictionaryNode
				.getStringIgnoreCase(Properties.REQUIRED_MSG);
		String strNullRepresent = dictionaryNode
				.getStringIgnoreCase(Properties.NULL_REPRESENT);
		int iMaxLength = StringUtil.parseInt(
				dictionaryNode.getStringIgnoreCase(Properties.MAX_LENGTH), -1);

		String property = dictionaryNode
				.getStringIgnoreCase(Properties.PROPERTY_DATA_SOURCE);
		String unique = dictionaryNode
				.getStringIgnoreCase(Properties.PROPERTY_UNIQUE);
		if (!property.equals("") && component instanceof Field) {
			formData.getMapFieldData().put(property, (Field) component);

			if (unique.trim().equalsIgnoreCase(Properties.TRUE)) {
				formData.getListPropertyUnique().add(property);
			}
		}

		boolean bImmediate = StringUtil.parseBoolean(dictionaryNode
				.getStringIgnoreCase(Properties.IMMEDIATE));
		boolean bIsVisible = StringUtil.parseBoolean(
				dictionaryNode.getStringIgnoreCase(Properties.VISIBLE), true);
		boolean bIsReadOnly = StringUtil.parseBoolean(dictionaryNode
				.getStringIgnoreCase(Properties.READ_ONLY));
		boolean bRequired = StringUtil.parseBoolean(dictionaryNode
				.getStringIgnoreCase(Properties.REQUIRED));

		if (!strWidth.equals(""))
			component.setWidth(strWidth);

		if (!strHeight.equals(""))
			component.setHeight(strHeight);

		if (!strIcon.equals(""))
			component.setIcon(new ThemeResource(strIcon));

		if (!strResource.equals(""))
			component.setCaption(TM.get(strResource));

		if (!strTitle.equals(""))
			component.setCaption(TM.get(strTitle));

		component.setVisible(bIsVisible);
		component.setReadOnly(bIsReadOnly);

		if (component instanceof AbstractComponent) {

			if (!strDescription.equals(""))
				((AbstractComponent) component).setDescription(TM
						.get(strDescription));

			((AbstractComponent) component).setImmediate(bImmediate);

		}

		if (component instanceof AbstractField) {

			int tabIndex = StringUtil.parseInt(
					dictionaryNode.getStringIgnoreCase(Properties.TAB_INDEX),
					-1);

			if (tabIndex > -1)
				((AbstractField) component).setTabIndex(tabIndex);

			((AbstractField) component).setRequired(bRequired);
			((AbstractField) component).setRequiredError(TM
					.get(strRequiredMessage));

		}

		if (component instanceof AbstractTextField) {

			setInputPrompt(dictionaryNode, (AbstractTextField) component);

			if (iMaxLength > -1)
				((AbstractTextField) component).setMaxLength(iMaxLength);

			if (!strNullRepresent.equals(""))
				((AbstractTextField) component)
						.setNullRepresentation(strNullRepresent);

		}

	}

	private void setInputPrompt(DictionaryNode dictionaryNode,
			AbstractTextField control) {

		String strInputPrompt = dictionaryNode
				.getStringIgnoreCase(Properties.INPUT_PROMPT);

		if (!strInputPrompt.equals(""))
			control.setInputPrompt(TM.get(strInputPrompt));

	}

	public VaadinFormBuilderImpl(ComponentContainer form) {

		this.form = form;

		controlCreator = new ControlCreatorImpl();
		layoutBuilder = new LayoutBuilderImpl();

	}

}
